class Language:
    WORD = 1
    NUMBER = 2
    SPECIAL_CHAR = 3
    SPACE = 7
    END = 4
    EMPTY = 5
    
    special_chars = [ '#', '=', ',', ';', ':', '<', '>', '{', '}', '(', ')', '+', '-', '*', '/', '\\', '.', '"', "'", '[', ']', '!', '@', '^',
                      '^', '&', '~', '/', '%', '|','?','`' ]
    def __init__( self, filename = None ):
        if not filename:
            raise Exception( "Please provide the file name" )
        else:
            self.filename = filename
            self.infile = open( filename )
            self.buffer = []
            self.forward = 0
            self.line = ""
            self.length = 0
            
            # read the first line.
            self.line, self.length = self.getNextLine()
    
    def getToken( self ):
        
        char = ""
        token = []
        spaces = []
        # if space, skip but keep only one space.
        while True:
            if self.forward >= self.length:
                self.line, self.length = self.getNextLine()
                if self.length == 0:
                    return ( '', Language.END )
                self.forward = 0
            char = self.line[ self.forward ]
            if char == ' ' or char == '\t' or char == '\n':
               token.append( char )
               self.forward += 1
            else:
                # i have seen a white space.
                # all the seen white spaces will be returned to the user of the lexer.
                # he has to decide which white space needs to be used.[ first, all or recent ]
                if token:
                    return ( "".join( token ), Language.SPACE )
                else:
                    break
        
        # check for word.
        while True:
            if self.forward >= self.length:
                self.line, self.length = self.getNextLine()
                if self.length == 0:
                    return ( '', Language.END )
                self.forward = 0
            char = self.line[ self.forward ]
            if ( ord( char ) >= 65 and ord( char ) <= 90 ) or ( ord( char ) >= 97 and ord( char ) <= 122 ) or char == '_':
                token.append( char )
                self.forward += 1
            else:
                # if i found a token, then return it.
                if len( token ) > 0:
                    return ( "".join( token ), Language.WORD )
                else:
                    # get out of the loop to see other tokens.
                    break
        
        # check for numbers.[ identifies only integers ]
        while True:
            if self.forward >= self.length:
                self.line, self.length = self.getNextLine()
                if self.length == 0:
                    return ( '', Language.END )
                else:
                    self.forward = 0
            char = self.line[ self.forward ]
            if  ord( char ) >= 48 and ord( char ) <= 57:
                token.append( char )
                self.forward += 1
            else:
                # if i found a token, then return it.
                if len( token ) > 0:
                    return( "".join( token ), Language.NUMBER )
                else:
                    # get out of the loop to see other tokens.
                    break
        
        # check for special characters.
        while True:
            if self.forward >= self.length:
                self.line, self.length = self.getNextLine()
                if self.length == 0:
                    return ( '', Language.END )
                else:
                    self.forward = 0
            char = self.line[ self.forward ]
            if char in Language.special_chars:
                self.forward += 1
                return ( char, Language.SPECIAL_CHAR )
            else:
                return ( '', Language.EMPTY )
        
    def getNextLine( self ):
        line = self.infile.readline()
        return ( line, len( line ) )
    
    def push( self, token ):
        self.buffer.append( token )
    def pop( self ):
        self.buffer.pop()
        
    def peek( self, char ):
        prev_fposition = self.infile.tell()
        prev_line = self.line
        prev_length = self.length;
        prev_forward = self.forward
        flag = False
        while True:
            token, state = self.getToken()
            if state == Language.SPACE:
                continue
            else:
                if token == char:
                    flag = True
                break
        # reset the file pointer.
        self.infile.seek( prev_fposition, 0 )
        self.line = prev_line
        self.length = prev_length;
        self.forward = prev_forward
        return flag

    def write( self, filename = None ):
        self.infile.close()
        if filename:
            f = open( filename, mode = "w" )
        else:
            f = open( self.filename, mode = "w" )
        f.write( "".join( self.buffer ) )
        f.close()
